/*
 *** DOES NOT USE BUILT-IN DETECTION FUNCTION ***
 
alert tcp $EXTERNAL_NET [1863,3128,80,8080] -> $HOME_NET any (msg: "WEB-MISC Pidgin MSN MSNP2P message integer overflow attempt"; flow: established, to_client; content: "application/x-msnmsgrp2p"; nocase; content: "P2P-Dest"; nocase; pcre:"/P2P-Dest[^\n]*\n\r?\n/i"; classtype: misc-attack; reference: cve, 2008-2927; reference:bugtraq, 29956;  reference:cve,2009-1376;  reference:cve,2009-2694; metadata:policy balanced-ips drop, policy security-ips drop; sid: 14263;)
*/
/*
 * Use at your own risk.
 *
 * Copyright (C) 2005-2008 Sourcefire, Inc.
 * 
 * This file is autogenerated via rules2c, by Brian Caswell <bmc@sourcefire.com>
 */


#include "sf_snort_plugin_api.h"
#include "sf_snort_packet.h"

#include "so-util.h"

//#define DEBUG 1
#ifdef DEBUG
#define DEBUG_WRAP(code) code
#else
#define DEBUG_WRAP(code)
#endif

/* declare detection functions */
int rule14263eval(void *p);

/* declare rule data structures */
/* precompile the stuff that needs pre-compiled */
/* flow:established, to_client; */
static FlowFlags rule14263flow0 = 
{
    FLOW_ESTABLISHED|FLOW_TO_CLIENT
};

static RuleOption rule14263option0 =
{
    OPTION_TYPE_FLOWFLAGS,
    {
        &rule14263flow0
    }
};
// content:"application/x-msnmsgrp2p", nocase; 
static ContentInfo rule14263content1 = 
{
    (uint8_t *) "application/x-msnmsgrp2p", /* pattern (now in snort content format) */
    0, /* depth */
    0, /* offset */
    CONTENT_NOCASE|CONTENT_BUF_NORMALIZED, /* flags */ // XXX - need to add CONTENT_FAST_PATTERN support
    NULL, /* holder for boyer/moore PTR */
    NULL, /* more holder info - byteform */
    0, /* byteform length */
    0 /* increment length*/
};

static RuleOption rule14263option1 = 
{
    OPTION_TYPE_CONTENT,
    {
        &rule14263content1
    }
};
// content:"P2P-Dest", nocase; 
static ContentInfo rule14263content2 = 
{
    (uint8_t *) "P2P-Dest", /* pattern (now in snort content format) */
    0, /* depth */
    0, /* offset */
    CONTENT_NOCASE|CONTENT_BUF_NORMALIZED, /* flags */ // XXX - need to add CONTENT_FAST_PATTERN support
    NULL, /* holder for boyer/moore PTR */
    NULL, /* more holder info - byteform */
    0, /* byteform length */
    0 /* increment length*/
};

static RuleOption rule14263option2 = 
{
    OPTION_TYPE_CONTENT,
    {
        &rule14263content2
    }
};
// pcre:"P2P-Dest[^\n]*\n\r?\n", nocase;
static PCREInfo rule14263pcre3 =
{
    "^P2P-Dest[^\\n]*\\n\\r?\\n", /* pattern */
    NULL,                               /* holder for compiled pattern */
    NULL,                               /* holder for compiled pattern flags */
    PCRE_CASELESS|PCRE_DOTALL|PCRE_MULTILINE,     /* compile flags */
    CONTENT_BUF_NORMALIZED     /* content flags */
};


static RuleOption rule14263option3 =
{
    OPTION_TYPE_PCRE,
    {
        &rule14263pcre3
    }
};

/* references for sid 14263 */
/* reference: bugtraq "29956"; */
static RuleReference rule14263ref1 = 
{
    "bugtraq", /* type */
    "29956" /* value */
};

/* reference: cve "2008-2927"; */
static RuleReference rule14263ref2 = 
{
    "cve", /* type */
    "2008-2927" /* value */
};

/* reference: cve "2009-1376"; */
static RuleReference rule14263ref3 = 
{
    "cve", /* type */
    "2009-1376" /* value */
};

/* reference: cve "2009-2694"; */
static RuleReference rule14263ref4 = 
{
    "cve", /* type */
    "2009-2694" /* value */
};

static RuleReference *rule14263refs[] =
{
    &rule14263ref1,
    &rule14263ref2,
    &rule14263ref3,
    &rule14263ref4,
    NULL
};

/* metadata for sid 14263 */
/* metadata:policy balanced-ips drop, policy security-ips drop; */

static RuleMetaData rule14263service1 =
{
    "service http"
};

static RuleMetaData rule14263policy1 = 
{
    "policy balanced-ips drop"
};

static RuleMetaData rule14263policy2 = 
{
    "policy security-ips drop"
};

static RuleMetaData rule14263policy3 = 
{
    "policy max-detect-ips drop"
};

static RuleMetaData *rule14263metadata[] =
{
    &rule14263service1,
    &rule14263policy1,
    &rule14263policy2,
    &rule14263policy3,
    NULL
};

RuleOption *rule14263options[] =
{
    &rule14263option0,
    &rule14263option1,
    &rule14263option2,
    &rule14263option3,
    NULL
};

Rule rule14263 = {
   
   /* rule header, akin to => tcp any any -> any any               */{
       IPPROTO_TCP, /* proto */
       "$EXTERNAL_NET", /* SRCIP     */
       "[1863,3128,80,8080]", /* SRCPORT   */
       0, /* DIRECTION */
       "$HOME_NET", /* DSTIP     */       
       "any" /* DSTPORT   */
   },
   /* metadata */
   { 
       3,  /* genid (HARDCODED!!!) */
       14263, /* sigid */
       8, /* revision */
   
       "attempted-user", /* classification */
       0,  /* hardcoded priority XXX NOT PROVIDED BY GRAMMAR YET! */
       "POLICY-SOCIAL Pidgin MSN MSNP2P message integer overflow attempt",     /* message */
       rule14263refs /* ptr to references */
       ,rule14263metadata
   },
   rule14263options, /* ptr to rule options */
   &rule14263eval, /* use the built in detection function */
   0 /* am I initialized yet? */
};


/* detection functions */
int rule14263eval(void *p) {
    const uint8_t *cursor_normal = 0;
    SFSnortPacket *sp = (SFSnortPacket *) p;
    
    const uint8_t *beg_of_payload, *end_of_payload;
    const uint8_t *cursor_temp;

    uint32_t length, offset_32;
    uint64_t total_size, offset_64;
    uint32_t flags;

    DEBUG_WRAP(const char *name="rule14263eval";)
    DEBUG_WRAP(printf("%s: enter\n", name);)
  
    if(sp == NULL)
        return RULE_NOMATCH;

    if(sp->payload == NULL)
        return RULE_NOMATCH;

    // flow:established, to_client;
    if (checkFlow(p, rule14263options[0]->option_u.flowFlags) > 0 ) {

          // The first content match doesn't need to be run again; essentially just there for fast
          // pattern. The second content match is repeated as part of the pcre, which is not relative
          // to the content match.  This means checking either content match here is a waste of cycles.

//        // content:"application/x-msnmsgrp2p", nocase;
//        if (contentMatch(p, rule14263options[1]->option_u.content, &cursor_normal) > 0) {
//            // content:"P2P-Dest", nocase;
//            if (contentMatch(p, rule14263options[2]->option_u.content, &cursor_normal) > 0) {
                // pcre:"P2P-Dest[^\n]*\n\r?\n", nocase;
                if (pcreMatch(p, rule14263options[3]->option_u.pcre, &cursor_normal)) {
                    if(getBuffer(sp, CONTENT_BUF_NORMALIZED, &beg_of_payload, &end_of_payload) <= 0)
                       return RULE_NOMATCH;

                    if ((cursor_normal + 32) > end_of_payload)
                        return RULE_NOMATCH;
                    
                    // to handle cve-2008-2927 and 2009-1376                    
                    cursor_temp = cursor_normal + 8;
                    offset_64  = read_little_64(cursor_temp);
                    offset_32  = (uint32_t)offset_64;    // 8 byte offset field used to be casted to 4 byte gsize

                    cursor_temp += 16;
                    length = read_little_32(cursor_temp); 

                    DEBUG_WRAP(printf("offset_64 [%llu]  length [%u]\n", offset_64, length);)

                    // If offset field is too big, it is a suspicious packet and we can alert ASAP rather than checking other conditions  
                    // If length + offset causes negative number or integer overflow, alert
                    if(((length + offset_32) > 0x7fffffff) || ((length + offset_32) < length))
                        return RULE_MATCH;
                    
                    

                    // to handle cve-2009-2694
                    // The following condition detects a bogus packet that is used to create a slpmsg structture
                    // Note that there can be an alternative way to bypass the detection
                        
                    DEBUG_WRAP(printf("cursor_normal + 48 + 4 [%p] end_of_payload [%p]\n", cursor_normal + 48 + 4, end_of_payload);)

                    // If offset == 0, slpmsg is created
                    // If length > 0 but body is empty, which is suspicious. 48 == header size, 4 == tail size (usually 0x00000000)
                    if ((offset_64 == 0) && (length > 0) && (end_of_payload <= cursor_normal + 48 + 4)) 
                    {                        
                        cursor_temp = cursor_normal + 16;
                        total_size = read_little_64(cursor_temp);
                        DEBUG_WRAP(printf("total_size [%llu]\n", total_size);)
                        
                        cursor_temp += 12;
                        flags = read_little_32(cursor_temp);                        
                        DEBUG_WRAP(printf("flags [0x%x]\n", flags);)
                        
                        if ((total_size == length) &&  
                            (flags == 0x00 || flags == 0x1000000 ||    // flags that makes pidgin sends ACK, 
                             flags == 0x20 || flags == 0x1000020 ||    // pidgin did not delete slpmsg structure after sending ACK and slpmsg is used for an attack
                             flags == 0x1000030))
                        {
                            return RULE_MATCH;
                        }
                    }
                }
//            }
//        }
    }
    return RULE_NOMATCH;
}

/*
Rule *rules[] = {
    &rule14263,
    NULL
};
*/

